package com.tian.service.impl;

import com.alibaba.fastjson.JSON;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.tian.common.CommonResult;
import com.tian.dto.*;
import com.tian.entity.ChargeRecord;
import com.tian.entity.ChargeStationGun;
import com.tian.entity.ChargeStationInfo;
import com.tian.enums.ChargerGunStatusEnum;
import com.tian.enums.ChargingStatusEnum;
import com.tian.enums.ChargingPayStatusEnum;
import com.tian.enums.ResultCode;
import com.tian.mapper.ChargeRecordMapper;
import com.tian.mapper.ChargeStationGunMapper;
import com.tian.mapper.ChargeStationInfoMapper;
import com.tian.mqtt.enums.MqttTopicEnum;
import com.tian.mqtt.message.ChargerStopPublishMessage;
import com.tian.netty.executor.ChargingFlowService;
import com.tian.service.ChargeRecordService;
import com.tian.util.*;
import lombok.extern.slf4j.Slf4j;
import org.eclipse.paho.client.mqttv3.MqttClient;
import org.eclipse.paho.client.mqttv3.MqttException;
import org.eclipse.paho.client.mqttv3.MqttMessage;
import org.redisson.api.RBucket;
import org.redisson.api.RedissonClient;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;

/**
 * {@code @description:} 充电记录
 *
 * @author tianwc 公众号：Java后端技术全栈
 * 在线刷题 1200+java面试题和1000+篇技术文章：<a href="https://woaijava.cc/">博客地址</a>
 * {@code @date:} 2024/2/20 20:48
 * {@code @version:} 1.0
 */
@Slf4j
@Service
public class ChargeRecordServiceImpl implements ChargeRecordService {
    @Resource
    private MqttClient client4Publish;
    @Resource
    private ChargeRecordMapper chargeRecordMapper;
    @Resource
    private ChargeStationGunMapper chargeStationGunMapper;
    @Resource
    private ChargeStationInfoMapper chargeStationInfoMapper;
    @Resource
    private RedissonClient redissonClient;
    @Resource
    private ChargingFlowService chargingFlowService;

    @Transactional(rollbackFor = Exception.class)
    @Override
    public CommonResult<Boolean> startCharge(ChargingStartReqDto chargingStartReqDto) {
        if (StringUtil.isEmpty(chargingStartReqDto.getGunNo())) {
            log.error("gunNo参数不能为空");
            return CommonResult.failed(ResultCode.PARAMETER_EMPTY.getCode(), "gunNo参数不能为空");
        }
        ChargeStationGun chargeGun = chargeStationGunMapper.selectByGunNo(chargingStartReqDto.getGunNo());
        if (chargeGun == null) {
            log.error("请求参数gunNo有误，request gunNo={}", chargingStartReqDto);
            return CommonResult.failed(ResultCode.PARAMETER_EMPTY.getCode(), "gunNo参数有误");
        }
        if (chargeGun.getStatus() != ChargerGunStatusEnum.IDLE.getChargerStatus()) {
            String byStatus = ChargerGunStatusEnum.getByStatus(chargeGun.getStatus());
            log.error("枪{}正在{}中，不能使用", chargeGun.getGunNo(), byStatus);
            return CommonResult.failed(ResultCode.GUN_ERROR);
        }
        ChargeRecord chargerRecord = chargeRecordMapper.selectByChargeGunId(chargeGun.getId());
        if (chargerRecord !=null) {
            log.error("重复请求，枪{}正在充电中，不能重复充电", chargeGun.getGunNo());
            return CommonResult.success(Boolean.TRUE);
        }
        ChargeUserLoginResDto user = UserCacheUtil.getUser();
        ChargeStationInfo charger = chargeStationInfoMapper.selectByPrimaryKey(chargeGun.getStationId());

        chargerRecord = new ChargeRecord();
        chargerRecord.setStationGunId(chargeGun.getId());
        chargerRecord.setUserId(user.getId());
        chargerRecord.setPayStatus(ChargingPayStatusEnum.INIT.getPayStatus());
        chargerRecord.setPrice(charger.getPrice());
        chargerRecord.setStartTime(new Date());
        chargerRecord.setCreateTime(new Date());
        chargerRecord.setQuantity(BigDecimal.ZERO);
        chargerRecord.setChargeStatus(ChargingStatusEnum.CHARGING.getStatus());

        chargeRecordMapper.insert(chargerRecord);
//
//        JSONObject params = new JSONObject();
//        params.put("chargerNo", chargeGun.getGunNo());
//        params.put("orderId", chargerRecord.getId());
//
//        //发送启动电桩指令
//        Future<Object> sendMsgFuture = chargingFlowService.sendStarChargerMsg(params);
//
//        try {
//            if (sendMsgFuture == null || !sendMsgFuture.get().equals("success")) {
//                return CommonResult.failed(ResultCode.CHARGING_START_FAILED);
//            }
//        } catch (Exception e) {
//            log.error("发送启动电桩指令失败", e);
//            return CommonResult.failed(ResultCode.CHARGING_START_FAILED);
//        }
        return CommonResult.success(Boolean.TRUE);
    }

    @Override
    public void doStartCharge(ChargeRecordAddReqDto chargerRecordAddReqDto) {

    }

    @Override
    public CommonResult<ChargeRecordUpdateRespDto> readyStopCharge(ChargeRecordUpdateReqDto
                                                                           chargerRecordUpdateReqDto) {
        Long id = chargerRecordUpdateReqDto.getId();
        ChargeRecord chargerRecord = chargeRecordMapper.selectByPrimaryKey(id);

        ChargeUserLoginResDto user = UserCacheUtil.getUser();

        ChargeStationGun chargeGun = chargeStationGunMapper.selectByPrimaryKey(chargerRecord.getStationGunId());

        ChargerStopPublishMessage chargerStopMessage = new ChargerStopPublishMessage();
        chargerStopMessage.setName(chargeGun.getGunName());
        chargerStopMessage.setUserId(user.getId());
        chargerStopMessage.setGunNo(chargeGun.getGunNo());
        MqttMessage message = new MqttMessage();
        message.setQos(0);
        message.setPayload(JSON.toJSONString(chargerStopMessage).getBytes());
        try {
            //发送指令  充电结，设备那边根据发过去的指令进行充电结束，再发充电结束指令 回  系统里
            client4Publish.publish(MqttTopicEnum.CHARGER_STOP_CHARGER_GUN.getTopicName(), message);
        } catch (MqttException e) {
            throw new RuntimeException(e);
        }
        return CommonResult.success();
    }

    @Override
    public CommonResult<ChargeRecordRespDto> doStopCharge() {
        ChargeUserLoginResDto user = UserCacheUtil.getUser();
        Long id = user.getId();

        ChargeRecord chargerRecord = chargeRecordMapper.selectByByUserId(id);
        if (chargerRecord.getChargeStatus() != ChargingStatusEnum.CHARGING.getStatus()) {
            return getChargeRecordRespDtoCommonResult(chargerRecord);
        }

        Integer stationGunId = chargerRecord.getStationGunId();

        RBucket<String> chargeStationGunBucket = redissonClient.getBucket(StationRedisPreKey.STATION_GUN_PRE_KEY + stationGunId);
        ChargeStationGun chargeGun = JSON.parseObject(chargeStationGunBucket.get(), ChargeStationGun.class);
        Date endTime = new Date();
        BigDecimal price = chargerRecord.getPrice();
        //如果设备端无法计算电量度数，那就使用功率乘以  (结束时间-开始时间) 分钟单位，再除以60.
        BigDecimal quantity = new BigDecimal(chargeGun.getGunPower());

        BigDecimal money = price.multiply(quantity);

        chargerRecord.setAmount(money);
        chargerRecord.setEndTime(endTime);
        chargerRecord.setQuantity(quantity);
        chargerRecord.setChargeStatus(ChargingStatusEnum.CHARGED.getStatus());
        chargeRecordMapper.updateByPrimaryKey(chargerRecord);
        return getChargeRecordRespDtoCommonResult(chargerRecord);
    }

    private static CommonResult<ChargeRecordRespDto> getChargeRecordRespDtoCommonResult(ChargeRecord chargerRecord) {
        ChargeRecordRespDto chargerRecordRespDto = new ChargeRecordRespDto();
        BeanUtils.copyProperties(chargerRecord, chargerRecordRespDto);
        BigDecimal amount = chargerRecord.getAmount();
        amount = amount.setScale(2, RoundingMode.HALF_UP);
        chargerRecordRespDto.setAmountStr(amount.toString());
        return CommonResult.success(chargerRecordRespDto);
    }

    @Override
    public CommonResult<ChargeRecordRespDto> selectById(Long id) {
        ChargeRecord chargerRecord = chargeRecordMapper.selectByPrimaryKey(id);
        ChargeRecordRespDto chargerRecordRespDto = ChargeRecordConvert.convert4SelectById();
        return CommonResult.success(chargerRecordRespDto);
    }

    @Override
    public CommonResult<ChargeRecordPageRespDto> page(ChargeRecordPageReqDto chargerRecordPageReqDto) {
        return null;
    }

    @Override
    public CommonResult<ChargeTimesCountRespDto> chargeTimesCount(String date) {
        Date queryDate = DateUtils.parse(date, DateUtils.FORMAT_DATE);
        int chargeTimesCount = chargeRecordMapper.chargeTimesCount(queryDate);
        ChargeTimesCountRespDto chargeTimesCountRespDto = new ChargeTimesCountRespDto();
        chargeTimesCountRespDto.setCount(chargeTimesCount);
        chargeTimesCountRespDto.setDate(date);
        return CommonResult.success(chargeTimesCountRespDto);
    }

    @Override
    public CommonResult<ChargeTimesCountRespDto> chargeTimesCountLasMonth() {
        Date date = new Date();
        String lastMonth = DateUtils.formatDateTime(DateUtils.add(date, Calendar.DAY_OF_MONTH, -1));
        RBucket<Integer> bucket = redissonClient.getBucket(RedisConstantPre.MONTH_COUNT_STATISTICS_CHARGE + lastMonth);
        Integer count = bucket.get();
        ChargeTimesCountRespDto chargeTimesCountRespDto = new ChargeTimesCountRespDto();
        chargeTimesCountRespDto.setDate(lastMonth);

        chargeTimesCountRespDto.setCount(count == null ? 0 : count);
        return CommonResult.success();
    }

    @Override
    public CommonResult<ChargingDataRespDto> chargingData(ChargingStartReqDto chargingStartReqDto) {

//        RBucket<String> bucket = redissonClient.getBucket(RedisConstantPre.CHARGING_RECORD_PRE + chargingStartReqDto.getChargingRecordId());
//        Date startTime = null;
//        if (StringUtil.isBlank(bucket.get())) {
//            ChargeRecord chargeRecord = chargeRecordMapper.selectByPrimaryKey(chargingStartReqDto.getChargingRecordId());
//            startTime = chargeRecord.getStartTime();
//            bucket.set(JSON.toJSONString(chargeRecord));
//        } else {
//            ChargeRecord chargeRecord = JSON.parseObject(bucket.get(), ChargeRecord.class);
//            startTime = chargeRecord.getStartTime();
//        }

//        QueryModel queryModel = new QueryModel();
//        Map<String, Object> map = new TreeMap<>();
//        map.put("gun_no", chargingStartReqDto.getGunNo());
//        map.put("charge_record_id", chargingStartReqDto.getChargingRecordId().toString());
//        queryModel.setMeasurement(InfluxdbUtils.getMeasurement(ChargingData.class));
//        queryModel.setMap(map);
//        queryModel.setStart(startTime.toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime());
//        queryModel.setEnd(LocalDateTime.now());
//        queryModel.setOrder(Order.DESC);
//        queryModel.setWhere(Op.where(queryModel) + " LIMIT 1");
//        queryModel.setWhere(Op.where(queryModel));
//        List<ChargingData> chargingDataList = influxDBTemplate.selectList(Query.build(queryModel), ChargingData.class);
//        if (chargingDataList.isEmpty()) {
//            return CommonResult.failed(ResultCode.CHARGE_DATA_NOT_EXIST);
//        }
//        ChargingData chargingData = chargingDataList.get(0);
//        ChargingDataRespDto chargingDataRespDto = new ChargingDataRespDto();
//        chargingDataRespDto.setGunNO(chargingStartReqDto.getGunNo());
//        chargingDataRespDto.setChargingNum(chargingData.getChargeNum());
//        chargingDataRespDto.setChargingNumMost();
//        return CommonResult.success(chargingDataRespDto);
        return CommonResult.success();
    }

    @Override
    public CommonResult<ChargeRecordPageRespDto> getChargeRecordList(ChargeRecordPageReqDto chargeRecordPageReqDto) {
        int pageNum = chargeRecordPageReqDto.getPageNum() == null ? 1 : chargeRecordPageReqDto.getPageNum();
        int pageSize = chargeRecordPageReqDto.getPageSize() == null ? 10 : chargeRecordPageReqDto.getPageSize();

        Page<ChargeRecord> page = PageHelper.startPage(pageNum, pageSize);

        chargeRecordPageReqDto.setUserId(UserCacheUtil.getUser().getId());
        List<ChargeRecord> chargeRecordList = chargeRecordMapper.listByByUserId(chargeRecordPageReqDto);

        ChargeRecordPageRespDto chargeRecordPageRespDto = new ChargeRecordPageRespDto();
        chargeRecordPageRespDto.setTotal(page.getTotal());
        chargeRecordPageRespDto.setPageSize(pageSize);
        chargeRecordPageRespDto.setPageNum(pageNum);

        List<ChargeRecordRespDto> data = new ArrayList<>();
        for (ChargeRecord chargeRecord : chargeRecordList) {
            ChargeRecordRespDto chargeRecordRespDto = new ChargeRecordRespDto();
            BeanUtils.copyProperties(chargeRecord, chargeRecordRespDto);
            chargeRecordRespDto.setAmountStr(chargeRecord.getAmount().setScale(2, RoundingMode.HALF_UP).toString());

            RBucket<String> chargeStationGunBucket = redissonClient.getBucket(StationRedisPreKey.STATION_GUN_PRE_KEY + chargeRecord.getStationGunId());
            ChargeStationGun chargeGun = JSON.parseObject(chargeStationGunBucket.get(), ChargeStationGun.class);
            chargeRecordRespDto.setGunName(chargeGun.getGunName());
            chargeRecordRespDto.setStationName(chargeGun.getStationName());
            chargeRecordRespDto.setGunNo(chargeGun.getGunNo());
            chargeRecordRespDto.setCreateTimeStr(DateUtils.formatDateTime(chargeRecord.getCreateTime()));
            data.add(chargeRecordRespDto);
        }
        chargeRecordPageRespDto.setData(data);
        return CommonResult.success(chargeRecordPageRespDto);
    }
}
